import { BASE_API, FETCH_API } from '@/config'
import { getChain } from '@/store/chain'
import { clearToken, getToken } from '@/store/token'
import { ResError, Result } from '@/types/api'
import axios, { AxiosError, AxiosRequestConfig } from 'axios'
import { Logger } from './log'

const service = axios.create({
  baseURL: BASE_API, // url = base url + request url
  withCredentials: true, // send cookies when cross-domain requests
  timeout: 90000 // request timeout
})

service.interceptors.request.use(
  config => {
    const token = getToken()
    config.headers['Content-Type'] = config.headers['Content-Type'] || 'application/json;charset=UTF-8'
    token ? (config.headers.Authorization = token) : (config.headers.Authorization = null)

    const chain = getChain()
    if (chain && !config.headers['chainId']) {
      config.headers['chainId'] = chain.id
    }
    return config
  },
  (error: Error) => Promise.reject(error)
)
service.interceptors.response.use(
  async response => {
    const { data: res, config, headers } = response
    const { code } = res
    if (code) {
      switch (code) {
        case 200:
          return res
        case 403:
          clearToken()
          return Promise.reject({ ...res, message: '登录失效，请重新登录' } as Error)
        default:
          return Promise.reject({ ...res, message: (res as { msg: string }).msg } as Error)
      }
    } else if (config.responseType === 'blob') {
      const blob = res as Blob
      const contentDisposition: string = headers['content-disposition'] || headers['Content-Disposition']
      const fileName = contentDisposition
        ? decodeURIComponent(contentDisposition.split('filename=')[1]?.trim().replace(/"/g, '') || '')
        : ''
      if (blob.type === 'application/json' && !fileName) {
        return new Promise((_, reject) => {
          const reader = new FileReader()
          reader.onload = function () {
            const error = JSON.parse(reader.result as string)
            reject({ ...error, message: (error as { msg: string }).msg } as Error)
          }
          reader.readAsText(blob)
        })
      }
      return {
        data: res,
        fileName
      }
    }
    return res
  },
  (error: Error) => Promise.reject(error)
)

function fetch<T>(url: string, data = {}, type = 'GET', rest: AxiosRequestConfig = {}): Promise<Result<T>> {
  const config = {
    method: type,
    url: FETCH_API + url,
    data,
    params: data
  }
  Object.assign(config, rest)
  if (type === 'POST' || type === 'PUT' || type === 'DELETE') {
    config.params = ''
  } else {
    config.data = ''
  }

  return new Promise((resolve, reject) => {
    service(config)
      .then(res => resolve(res as unknown as Result<T>))
      .catch((err: Error | AxiosError) => {
        Logger.error('[fetch-error]:', err)
        let newError
        if (err instanceof AxiosError) {
          newError = {
            code: err.code!,
            message: err.code === 'ECONNABORTED' ? '请求超时' : err.message,
            success: false
          } as ResError
        } else {
          newError = err
        }
        reject(newError)
      })
  })
}
export default fetch

export function urlParamToJson(urlParam?: string) {
  const json: Record<string, string | number> = {}
  urlParam &&
    urlParam
      .trim()
      .split('&')
      .forEach(item => (json[item.split('=')[0]] = item.split('=')[1]))

  return json
}
